/*
 * Packet.h
 *
 *  Created on: 2014. 6. 25.
 *      Author: jjaehuny
 */

#ifndef FRAMEWORK_NETWORK_PACKET_H_
#define FRAMEWORK_NETWORK_PACKET_H_

#include <memory>
#include <array>
#include <vector>

#include <google/protobuf/io/zero_copy_stream_impl_lite.h>

#include "../Macro.h"

namespace Framework { namespace Network {

class Packet;
std::shared_ptr<::Framework::Network::Packet> create_packet_multithread();
std::shared_ptr<::Framework::Network::Packet> create_packet_singlethread();


} /*Network*/ } /*Framework*/




namespace Framework { namespace Network {

class Packet : public std::enable_shared_from_this<Packet>
{
public:
	struct Header
	{
	public:
		Header() {}
		~Header() {}
		void clear() {}
	};

public:
	Packet();
	virtual ~Packet();

	Packet(const Packet & othre) = delete;
	Packet & operator= (const Packet & othre) = delete;

	void Initialize();
	void Finalize();

	std::shared_ptr<Packet> CAPTURE();

	template<class MSG>
	void Write(MSG & msg);

	char * Buffer();
	char * BodyBuffer() { return buffer_.data() + head_length_; }

	void resize(std::size_t size) { buffer_.resize(size); }
	std::size_t capacity() { return buffer_.capacity(); }

	template<class MSG>
	void make_message(MSG & msg) {
		int head_length = 4;
		this->set_head_length_(head_length);

		int bufSize = msg.ByteSize();

		// 버퍼에 직렬화
		google::protobuf::io::ArrayOutputStream os(this->BodyBuffer(), bufSize);
		msg.SerializeToZeroCopyStream(&os);

		this->set_send_length(bufSize + head_length);

		* this->Buffer() = static_cast<short>(bufSize);
		* (this->Buffer() + sizeof(short)) = static_cast<short>(msg.command());
	}

private:
	// property
	GETSETVAR(std::size_t, head_length_);
	GETSETVAR(std::size_t, body_length_);
	GETSETVAR(std::size_t, send_length);
	GETSETVAR(unsigned short, command);

	std::vector<char> buffer_;
	Header clsHeader_;
};

} /*Network*/ } /*Framework*/

#endif /* FRAMEWORK_NETWORK_PACKET_H_ */
